package com.xuecheng.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsSite;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.domain.cms.response.CmsPostPageResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.framework.model.response.ResultCode;
import com.xuecheng.manage_cms.config.RabbitmqConfig;
import com.xuecheng.manage_cms.dao.CmsConfigRepository;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsSiteRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * Created by Aniymx on 2018/12/17 11:02.
 */
@Service
public class CmsPageService {
    @Autowired
    private CmsPageRepository cmsPageRepository;

    //注入cmscongfigDao
    @Autowired
    private CmsConfigRepository cmsConfigRepository;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private CmsPageTemplateService cmsPageTemplateService;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private GridFSBucket gridFSBucket;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private CmsSiteRepository cmsSiteRepository;

    //查询所有页面
    public QueryResponseResult findAll(int page, int size, QueryPageRequest queryPageRequest) {
        //条件匹配器,模糊匹配
        ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());


        CmsPage cmsPage = new CmsPage();
        //根据输入的进行模糊查询
        if (StringUtils.isNotEmpty(queryPageRequest.getPageAliase())) {
            cmsPage.setPageAliase(queryPageRequest.getPageAliase());
        }

        //根据传递的站点信息进行匹配
        if (StringUtils.isNotEmpty(queryPageRequest.getSiteId())) {
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }

        Example<CmsPage> example = Example.of(cmsPage, exampleMatcher);


        //对用户传过来的page对象进行判断
        if (page < 0) {
            page = 1;
        }
        //因为page需要从0开始
        page = page - 1;
        //创建分页对象
        Pageable pageable = PageRequest.of(page, size);
        //查询出所有的页面
        Page<CmsPage> pages = cmsPageRepository.findAll(example, pageable);
        //创建状态码对象
        ResultCode resultCode = CommonCode.SUCCESS;
        //创建结果集对象
        QueryResult queryResult = new QueryResult();
        //把查询出的数据封装进结果集对象
        queryResult.setTotal(pages.getTotalElements());
        queryResult.setList(pages.getContent());
        //创建响应结果集对象,把上面的参数传进去
        QueryResponseResult queryResponseResult = new QueryResponseResult(resultCode, queryResult);
        //返回返回结果集,让controller进行调用
        return queryResponseResult;
    }
    /*
     *//*新增页面*//*
    public CmsPageResult addPage(CmsPage cmsPage) {
        //首先根据提交的信息进行查询,如果存在,返回失败错误码,成功则进行查询
        String siteId = cmsPage.getSiteId();
        String pageName = cmsPage.getPageName();
        String pageWebPath = cmsPage.getPageWebPath();
        CmsPage findCmsPage = cmsPageRepository.findBySiteIdAndPageNameAndPageWebPath(siteId, pageName, pageWebPath);
        if (findCmsPage == null) {
            cmsPage.setPageId(null);
            cmsPageRepository.save(cmsPage);
            return new CmsPageResult(CommonCode.SUCCESS, cmsPage);
        }
        return new CmsPageResult(CommonCode.FAIL, null);
    }*/


    /*新增页面*/
    public CmsPageResult addPage(CmsPage cmsPage) {
        //首先根据提交的信息进行查询,如果存在,返回失败错误码,成功则进行查询
        if (cmsPage == null) {
            //非法参数异常
        }
        String siteId = cmsPage.getSiteId();
        String pageName = cmsPage.getPageName();
        String pageWebPath = cmsPage.getPageWebPath();
        CmsPage findCmsPage = cmsPageRepository.findBySiteIdAndPageNameAndPageWebPath(siteId, pageName, pageWebPath);
        if (findCmsPage != null) {
            //已经存在
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
        }

        cmsPage.setPageId(null);
        cmsPageRepository.save(cmsPage);
        return new CmsPageResult(CommonCode.SUCCESS, cmsPage);
    }

    /*根据id查询页面业务层*/
    public CmsPage findById(String id) {

        Optional<CmsPage> optional = cmsPageRepository.findById(id);
        if (optional.isPresent()) {
            CmsPage cmsPage = optional.get();
            return cmsPage;
        }
        return null;
    }

    /*更新*///-------------------------================================
    public CmsPageResult updatePage(String id, CmsPage cmsPage) {
        /*先查,如果查到了对其进行更新*/ //根据id从数据库查询页面信息
        CmsPage one = this.findById(id);
        if (one != null) {
            //准备更新数据
            //设置要修改的数据
            //更新模板id
            one.setTemplateId(cmsPage.getTemplateId());
            //更新所属站点
            one.setSiteId(cmsPage.getSiteId());
            //更新页面别名
            one.setPageAliase(cmsPage.getPageAliase());
            //更新页面名称
            one.setPageName(cmsPage.getPageName());
            //更新访问路径
            one.setPageWebPath(cmsPage.getPageWebPath());
            //更新物理路径
            one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
            //更新dataUrl
            one.setDataUrl(cmsPage.getDataUrl());
            //提交修改
            cmsPageRepository.save(one);
            return new CmsPageResult(CommonCode.SUCCESS, one);
        }
        //修改失败
        return new CmsPageResult(CommonCode.FAIL, null);
    }

    /*删除页面*/
    public CmsPageResult deletePage(String id) {
        cmsPageRepository.deleteById(id);
        return new CmsPageResult(CommonCode.SUCCESS, null);
    }


    /*根据id查询CmsConfig的模型信息*/
    public CmsConfig getConfigById(String id) {
        Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
        if (optional.isPresent()) {
            CmsConfig cmsConfig = optional.get();
            return cmsConfig;
        }
        return null;
    }

    //==================================================================

    //根据pageid->page---template---file 取出file中的文件
    //静态化
    public String getPageHtml(String id) {

        Map model = this.getModelByPageId(id);
        if (model == null) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        String template = this.getTemplateByPageId(id);
        if (StringUtils.isEmpty(template)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        String html = this.generateHtml(template, model);
        return html;

    }

    //页面静态化,将数据和模板合并
    public String generateHtml(String temp, Map model) {
        try {
            Configuration configuration = new Configuration(Configuration.getVersion());
            StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
            stringTemplateLoader.putTemplate("template", temp);
            configuration.setTemplateLoader(stringTemplateLoader);
            Template template1 = configuration.getTemplate("template");
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template1, model);
            return html;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    //获取数据
    public Map getModelByPageId(String pageId) {
        CmsPage cmsPage = this.findById(pageId);
        if (cmsPage == null) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String dataUrl = cmsPage.getDataUrl();
        if (dataUrl == null) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        //使用模板获取数据
        ResponseEntity<Map> responseEntity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = responseEntity.getBody();
        return body;

    }

    //获取模板
    public String getTemplateByPageId(String PageId) {
        CmsPage cmsPage = this.findById(PageId);
        if (cmsPage == null) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String templateId = cmsPage.getTemplateId();
        if (StringUtils.isEmpty(templateId)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        CmsTemplate template = cmsPageTemplateService.findById(templateId);
        String templateFileId = template.getTemplateFileId();
        GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
        ObjectId objectId = gridFSFile.getObjectId();
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(objectId);
        GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
        try {
            String content = IOUtils.toString(gridFsResource.getInputStream(), "UTF-8");
            return content;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    //页面发布
    public CmsPageResult post(String id) {
        //传过来的id进行页面 静态化,得到文件内容,存进fs,发送mq消息,发布
        //得到页面内容
        String pageHtml = this.getPageHtml(id);
        if (StringUtils.isEmpty(pageHtml)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        //保存到fs
        CmsPage cmsPage = this.saveHtml(id, pageHtml);
        //发消息
        sendPostPage(id);
        return new CmsPageResult(CommonCode.SUCCESS, null);
    }

    //向mq进行发送消息
    public void sendPostPage(String pageId) {
        CmsPage cmsPage = this.findById(pageId);
        HashMap<String, String> map = new HashMap<>();
        map.put("pageId", pageId);
        String msg = JSON.toJSONString(map);
        String siteId = cmsPage.getSiteId();
        rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE, siteId, msg);
    }

    //保存静态页面内容
    public CmsPage saveHtml(String pageId, String content) {

        Optional<CmsPage> byId = cmsPageRepository.findById(pageId);
        if (!byId.isPresent()) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        CmsPage cmsPage = byId.get();
        String htmlFileId = cmsPage.getHtmlFileId();
        //根据htmlFileId先进行查询,删除后进行添加
        if (StringUtils.isNotEmpty(htmlFileId)) {
            gridFsTemplate.delete(Query.query(Criteria.where(htmlFileId).is("_id")));
        }
        InputStream inputStream = IOUtils.toInputStream(content);
        ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        String FileId = objectId.toString();
        //更新page表中的FileId
        cmsPage.setHtmlFileId(FileId);
        CmsPage save = cmsPageRepository.save(cmsPage);
        return save;
    }

    /*保存页面,有就更新,,没有进行保存操作*/
    public CmsPageResult save(CmsPage cmsPage) {
        //先进行查询
        CmsPage page = cmsPageRepository.findBySiteIdAndPageNameAndPageWebPath(cmsPage.getSiteId(), cmsPage.getPageName(), cmsPage.getPageWebPath());
        if (page != null) {
            //进行更新
            return this.updatePage(page.getPageId(), cmsPage);
        } else {
            //没有进行 新增
            return this.addPage(cmsPage);
        }

    }

    /*一键发布*/
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
        //CmsPage page = this.findById(cmsPage.getPageId());
      /*  //存到覆盖存储
        if (page!=null){
            cmsPage.setPageId(page.getPageId());
        }*/

        //先进行查询
     /*   CmsPage page = cmsPageRepository.findBySiteIdAndPageNameAndPageWebPath(cmsPage.getSiteId(), cmsPage.getPageName(), cmsPage.getPageWebPath());
        if (page != null) {
            //进行更新
            cmsPage.setPageId(page.getPageId());
        }*/
        CmsPageResult save = this.save(cmsPage);
        if (!save.isSuccess()) {
            return new CmsPostPageResult(CommonCode.FAIL, null);
        }
        //页面url=站点域名+站点webpath+页面webpath+页面名称
        CmsPage newCmsPage = save.getCmsPage();
        String pageId = newCmsPage.getPageId();
        //发布页面
        CmsPageResult postCmsPageResult = this.post(pageId);
        if (!postCmsPageResult.isSuccess()) {
            return new CmsPostPageResult(CommonCode.FAIL, null);
        }
        //拼接url


        CmsSite cmsSite = this.findSiteById(newCmsPage.getSiteId());
        //站点域名
        String siteDomain = cmsSite.getSiteDomain();
        //站点web路径
        String siteWebPath = cmsSite.getSiteWebPath();
        //页面web路径
        String pageWebPath = newCmsPage.getPageWebPath();
        //页面名称
        String pageName = newCmsPage.getPageName();
        //页面的web访问地址
        String url = siteDomain + siteWebPath + pageWebPath + pageName;

        return new CmsPostPageResult(CommonCode.SUCCESS, url);
    }

    private CmsSite findSiteById(String siteId) {
        Optional<CmsSite> byId = cmsSiteRepository.findById(siteId);
        if (byId.isPresent()) {
            return byId.get();
        }
        return null;
    }
}
